1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.base;
18  
19  import com.google.caliper.BeforeExperiment;
20  import com.google.caliper.Benchmark;
21  import com.google.caliper.Param;
22  import com.google.common.base.Strings;
23  
24  /**
25   * Microbenchmark for {@link Strings#repeat}
26   *
27   * @author Mike Cripps
28   */
29  public class StringsRepeatBenchmark {
30    @Param({"1", "5", "25", "125"}) int count;
31    @Param({"1", "10"}) int length;
32  
33    private String originalString;
34  
35    @BeforeExperiment void setUp() {
36      originalString = Strings.repeat("x", length);
37    }
38  
39    @Benchmark void oldRepeat(int reps) {
40      for (int i = 0; i < reps; i++) {
41        String x = oldRepeat(originalString, count);
42        if (x.length() != (originalString.length() * count)) {
43          throw new RuntimeException("Wrong length: "+x);
44        }
45      }
46    }
47    @Benchmark void mikeRepeat(int reps) {
48      for (int i = 0; i < reps; i++) {
49        String x = mikeRepeat(originalString, count);
50        if (x.length() != (originalString.length() * count)) {
51          throw new RuntimeException("Wrong length: "+x);
52        }
53      }
54    }
55    @Benchmark void martinRepeat(int reps) {
56      for (int i = 0; i < reps; i++) {
57        String x = martinRepeat(originalString, count);
58        if (x.length() != (originalString.length() * count)) {
59          throw new RuntimeException("Wrong length: "+x);
60        }
61      }
62    }
63  
64    private static String mikeRepeat(String string, int count) {
65      final int len = string.length();
66      char[] strCopy = new char[len * Integer.highestOneBit(count)];
67      string.getChars(0, len, strCopy, 0);
68  
69      char[] array = new char[len * count];
70  
71      int strCopyLen = len;
72      int pos = 0;
73      while (count != 0) {
74        if ((count & 1) != 0) {
75          System.arraycopy(strCopy, 0, array, pos,strCopyLen);
76          pos += strCopyLen;
77        }
78        count >>= 1;
79        if (count != 0) {
80          System.arraycopy(strCopy, 0, strCopy, strCopyLen, strCopyLen);
81          strCopyLen <<= 1;
82        }
83      }
84      return new String(array);
85    }
86  
87    private static String oldRepeat(String string, int count) {
88      // If this multiplication overflows, a NegativeArraySizeException or
89      // OutOfMemoryError is not far behind
90      final int len = string.length();
91      final int size = len * count;
92      char[] array = new char[size];
93      for (int i = 0; i < size; i+=len) {
94        string.getChars(0, len, array, i);
95      }
96      return new String(array);
97    }
98  
99    private static String martinRepeat(String string, int count) {
100     final int len = string.length();
101     final int size = len * count;
102     final char[] array = new char[size];
103     string.getChars(0, len, array, 0);
104     int n;
105     for (n = len; n < size - n; n <<= 1) {
106       System.arraycopy(array, 0, array, n, n);
107     }
108     System.arraycopy(array, 0, array, n, size - n);
109     return new String(array);
110   }
111 }